﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LockCrypt.Core;

namespace LockCrypt.DAL {
    public class DatabaseContents {
        public List<IAccount> Accounts { get; set; }
        public List<IGroup> Groups { get; set; }
        public List<ITemplate> Templates { get; set; }
        public DatabaseContents() {
            Accounts = new List<IAccount>();
            Groups = new List<IGroup>();
            Templates = new List<ITemplate>();
        }



        /// <summary>
        /// Synchronizes the contents of two databases, respecting the last modified time of all items in both.
        /// </summary>
        /// <param name="contents">The contents of the first database.</param>
        /// <param name="otherContents">The contents of the second database.</param>
        /// <returns>The combined and merged contents of both databases.</returns>
        public static DatabaseContents SynchronizeDatabases(DatabaseContents contents, DatabaseContents otherContents) {
            DatabaseContents merged = new DatabaseContents();
            Comparers.AccountComparer acountComp = new Comparers.AccountComparer();
            contents.Accounts.Sort(acountComp);
            otherContents.Accounts.Sort(acountComp);
            // if a account exists in either DB and not the other, copy it to the merged Db
            Action<IAccount> onAccountsOneDbOnly = merged.Accounts.Add;
            // if a account exists in both, check the Modified time
            Action<IAccount, IAccount> onAccountsBothDbs = (account, otherAccount) => {
                if(account.Modified > otherAccount.Modified) {
                    merged.Accounts.Add(account); // first account newer
                } else {
                    // either they're equal or the one in the second database is newer, either way we want the one from the second Db.
                    merged.Accounts.Add(otherAccount);
                }
            };
            SortedCollectionComparer.CompareSortedCollections<IAccount>(contents.Accounts, otherContents.Accounts, acountComp, onAccountsOneDbOnly, onAccountsOneDbOnly, onAccountsBothDbs);

            Comparers.GroupComparer groupComp = new Comparers.GroupComparer();
            contents.Groups.Sort(groupComp);
            otherContents.Groups.Sort(groupComp);
            Action<IGroup> onGropOneDbOnly = merged.Groups.Add;
            Action<IGroup, IGroup> onGroupBothDbs = (group, otherGroup) => merged.Groups.Add(group);
            SortedCollectionComparer.CompareSortedCollections<IGroup>(contents.Groups, otherContents.Groups, groupComp, onGropOneDbOnly, onGropOneDbOnly, onGroupBothDbs);

            Comparers.TemplateComparer templateComp = new Comparers.TemplateComparer();
            contents.Templates.Sort(templateComp);
            otherContents.Templates.Sort(templateComp);
            Action<ITemplate> onTemplateOneDbOnly = merged.Templates.Add;
            Action<ITemplate, ITemplate> onTemplateBothDbs = (template, otherTemplate) => merged.Templates.Add(template);
            SortedCollectionComparer.CompareSortedCollections<ITemplate>(contents.Templates, otherContents.Templates, templateComp, onTemplateOneDbOnly, onTemplateOneDbOnly, onTemplateBothDbs);
            return merged;
        }
    }
}
